import processing.core.PApplet;
import org.jbox2d.collision.*;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.*;
import org.jbox2d.dynamics.joints.*;

import java.awt.Dimension;
import java.io.*;
import java.net.*;
import java.util.*;


public class PelehockeyUI extends PApplet
{		
	
	String clientParams[];
	static ServerThread playersThread;
	int tmpXP1=0,tmpYP1=0,tmpXP2=0,tmpYP2=0,pointP1=0,pointP2=0;
	String[] clientIP;
	Boolean[] clientIPFix;
	
	private final int PTM_RATIO = 32;
	private AABB m_aabb;
	private Vec2 m_gravity;
	private Boolean m_do_sleep;
	private World m_world;
	//private Camera m_camera;
	private int fScreenW;
	private int fScreenH;
	private int ballx;
	private int bally;
	private int player1x;
	private int player1y;
	private int player2x;
	private int player2y;
	private Boolean firstTime;
	private Body ballBody;
	private Body player1Body;
	private Body player2Body;
	private MouseJoint mouseJointP1,mouseJointP2,mouseJointBall;
	
	public static void main(String[] args) 
	{	
		PApplet.main( new String[]{"Pelehockey.Main"} );
	}
	
	private Vec2 worldToScreen(Vec2 point)
	{
		return new Vec2(point.x * PTM_RATIO, point.y * PTM_RATIO);
	}
	
	private Vec2 screenToWorld(Vec2 point)
	{
		return new Vec2(point.x / PTM_RATIO, point.y / PTM_RATIO);		
	}
	
	private int worldToScreen(float f)
	{
		return (int) (f * PTM_RATIO);
	}
	
	private float screenToWorld(int f)
	{
		return (float) f / PTM_RATIO;		
	}
	
	@Override
	public void setup() 
	{
		
		firstTime=true;
		clientIPFix=new Boolean[2];
		clientIP=new String[2];
		clientIPFix[0]=false;
		clientIPFix[1]=false;
		Dimension d = getSize();
		fScreenW = d.width;
		fScreenH = d.height;		
		ballx = fScreenW/2;
		bally = fScreenH/2;
		player1x = 100;
		player1y = fScreenH/2;
		player2x = fScreenW-100;
		player2y = fScreenH/2;
		
		m_aabb = new AABB();
	    m_aabb.lowerBound = screenToWorld(new Vec2(-20, -20));
	    m_aabb.upperBound = screenToWorld(new Vec2(fScreenW+20, fScreenH+20));

	    m_do_sleep = true;
	    m_gravity = new Vec2(0.0f, 0.0f);
	    m_world = new World(m_aabb, m_gravity, m_do_sleep);
	    m_world.setContinuousPhysics(true);
	    
	    // create ground
	    BodyDef bd = new BodyDef();
		bd.position.set(0.0f, 0.0f);
		Body body = m_world.createBody(bd);

		PolygonDef sd = new PolygonDef();
		sd.density = 0.0f;
		sd.restitution = 0.0f;

		sd.setAsBox(screenToWorld(10), screenToWorld(fScreenH), 
					screenToWorld(new Vec2(fScreenW-1,0)), 0.0f); //right
		body.createShape(sd);

		sd.setAsBox(screenToWorld(10), screenToWorld(fScreenH), 
					screenToWorld(new Vec2(1, 0)), 0.0f); //left
		body.createShape(sd);

		sd.setAsBox(screenToWorld(fScreenW), screenToWorld(10), 
					screenToWorld(new Vec2(0, 1)), 0);//top
		body.createShape(sd);

		sd.setAsBox(screenToWorld(fScreenW), screenToWorld(10),  
					screenToWorld(new Vec2(0, fScreenH-1)), 0);//Bottom
		body.createShape(sd);
		
	    // create ball body
		BodyDef ballBodyDef = new BodyDef();
		ballBodyDef.position.set(screenToWorld(new Vec2(ballx, bally)));
		ballBody = m_world.createBody(ballBodyDef);
	 			
		CircleDef cd = new CircleDef();
		cd.radius = screenToWorld(16);
		cd.density = 0.1f;
		cd.restitution = 1.0f;
		cd.friction = 0.0f;
				
		ballBody.createShape(cd);
		ballBody.setMassFromShapes();
		
		// create player1 body
		BodyDef player1BodyDef = new BodyDef();
		player1BodyDef.position.set(screenToWorld(new Vec2(player1x, player1y)));
		player1Body = m_world.createBody(player1BodyDef);
		
		PolygonDef pd = new PolygonDef();
		pd.setAsBox(screenToWorld(35), screenToWorld(40));
		pd.density = 0.1f;
		pd.restitution = 0.0f;
		pd.friction = 0.0f;

		MassData md = new MassData();
		md.mass = 1000;
		md.center = screenToWorld(new Vec2(10, 20)); 
		player1Body.setMass(md);
		player1Body.createShape(pd);		
		
		// create player2 body
		BodyDef player2BodyDef = new BodyDef();
		player2BodyDef.position.set(screenToWorld(new Vec2(player2x, player2y)));
		player2Body = m_world.createBody(player2BodyDef);
		
		PolygonDef pd2 = new PolygonDef();
		pd2.setAsBox(screenToWorld(35), screenToWorld(40));
		pd2.density = 0.1f;
		pd2.restitution = 0f;
		pd2.friction = 0.0f;

		MassData md2 = new MassData();
		md2.mass = 1000;
		md2.center = screenToWorld(new Vec2(10, 20)); 		
		player2Body.setMass(md2);
		player2Body.createShape(pd2);
		
		
		// create mouse joint player1
	    MouseJointDef mjdP1 = new MouseJointDef();
        mjdP1.body1 = m_world.getGroundBody();
        mjdP1.body2 = player1Body;
        mjdP1.target = screenToWorld(new Vec2(mouseX, mouseY));
        mjdP1.maxForce = 1000.0f * player1Body.m_mass;
        mouseJointP1 = (MouseJoint) m_world.createJoint(mjdP1);
        
     // create mouse joint player2
	    MouseJointDef mjdP2 = new MouseJointDef();
        mjdP2.body1 = m_world.getGroundBody();
        mjdP2.body2 = player2Body;
        mjdP2.target = screenToWorld(new Vec2(mouseX, mouseY));
        mjdP2.maxForce = 1000.0f * player2Body.m_mass;
        mouseJointP2 = (MouseJoint) m_world.createJoint(mjdP2);
        
        //create server threads for every player;
        try {
			playersThread=new ServerThread();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        playersThread.start();
        
	}
	 
/*	 private int mousePressX;
	 private int mousePressY;
	 private boolean dragged = false;

	 public void mousePressed()
	 {
	 	dragged = true;
	 	
	 	// create mouse joint
	   /* MouseJointDef mjd = new MouseJointDef();
        mjd.body1 = m_world.getGroundBody();
        mjd.body2 = player1Body;
        mjd.target = screenToWorld(new Vec2(mouseX, mouseY));
        mjd.maxForce = 1000.0f * player1Body.m_mass;
        mouseJoint = (MouseJoint) m_world.createJoint(mjd);       
	 }
	 
	 public void mouseDragged()
	 {		 
	 	if (dragged)
	 	{ 
	    	mouseJoint.setTarget(screenToWorld(new Vec2(mouseX, mouseY)));
	    }
	 }
	 
	 public void mouseReleased()
	 {	 	
	 	mouseJoint = null;
	 	dragged = false;
	 }*/
	 
	 @Override
	 public void draw() 
	 {	
		 clientParams=playersThread.getValues();
		 playersThread.setDone("0");
		 if(clientParams[0]=="1"){
			 if(!clientIPFix[0])
			 {
				 clientIPFix[0]=true;
				 clientIP[0]=clientParams[1];
			 } else if (!clientIPFix[1] && clientIPFix[0] && !clientIP[0].equals(clientParams[1]) && clientIP[1]==null)
			{
					 clientIPFix[1]=true;
					 clientIP[1]=clientParams[1];
			} else if (clientIPFix[0] && clientIPFix[1]){
				 if(playersThread.getIP().equals(clientIP[0]))
				{ 
					 tmpXP1=Integer.parseInt(clientParams[2].substring(clientParams[2].indexOf("~")+1, clientParams[2].indexOf(":")));
					 tmpYP1=Integer.parseInt(clientParams[2].substring(clientParams[2].indexOf(":")+1));
				 } else if(playersThread.getIP().equals(clientIP[1])){
					 tmpXP2=Integer.parseInt(clientParams[2].substring(clientParams[2].indexOf("~")+1, clientParams[2].indexOf(":")));
					 tmpYP2=Integer.parseInt(clientParams[2].substring(clientParams[2].indexOf(":")+1)); 
				 }
				 if(firstTime)
				 {
					 firstTime=false;
					 Random rand = new Random();
					 double angle = rand.nextDouble()* 0.4f * Math.PI;
					 boolean direction = rand.nextBoolean();
					 if (direction) angle = angle + 0.25f * Math.PI;
					 else angle = angle + 0.75f * Math.PI;
					 double force = 10;
					 ballBody.applyForce(new Vec2((int)(force * Math.cos(angle)),(int)(force * Math.sin(angle))),ballBody.getPosition());
				 }
			 }
		 }
		 //ballBody.applyForce(new Vec2(1,1),ballBody.getPosition());
		 mouseJointP1.setTarget(screenToWorld(new Vec2(0,((fScreenH-40)/2)*-tmpYP1/1000)));
		 mouseJointP2.setTarget(screenToWorld(new Vec2(0,((fScreenH-40)/2)*tmpYP2/1000)));
		 m_world.step(1.0f/20, 10);
		 ballx = worldToScreen(ballBody.getPosition().x);
		 bally = worldToScreen(ballBody.getPosition().y);
		 player1x = worldToScreen(player1Body.getPosition().x);
		 player1y = worldToScreen(player1Body.getPosition().y);
		 player2x = worldToScreen(player2Body.getPosition().x);
		 player2y = worldToScreen(player2Body.getPosition().y);
		 
		 background(0,0,0);
		 color(255,255,255);		 

		 fill(255,255,255);
		 rect(15, 15, fScreenW-30, fScreenH-30);		 
		 
		 fill(0,255,0);
		 ellipse(ballx, bally, 32, 32);
		 
		 fill(255,0,0);
		 //ellipse(player1x, player1y, 48, 48);
		 rect(player1x - 20, player1y - 40, 40, 80);
		 
		 fill(0,0,255);
		 //ellipse(player2x, player2y, 48, 48);
		 rect(player2x - 20, player2y - 40, 40, 80);

		 if(ballx>fScreenW-50)
		 {
			 pointP1+=1;
			 firstTime=true;
			 destroyAndCreateBall();
		}
		 if(ballx<50)
		 {
			 pointP2+=1;
			 firstTime=true;
			 destroyAndCreateBall();
		 }
		 int fontheight=10;
		 int txtx=30,txty=30;
		 text("Blue:" + pointP2,txtx,txty);txty+=fontheight;
		 text("Red:" + pointP1,txtx,txty);txty+=fontheight;
	 }
	 
	 public void destroyAndCreateBall()
	 {
		 m_world.destroyBody(ballBody);
		 BodyDef ballBodyDef = new BodyDef();
		 ballx = fScreenW/2;
			bally = fScreenH/2;
			ballBodyDef.position.set(screenToWorld(new Vec2(ballx, bally)));
			ballBody = m_world.createBody(ballBodyDef);
		 			
			CircleDef cd = new CircleDef();
			cd.radius = screenToWorld(16);
			cd.density = 0.1f;
			cd.restitution = 1.0f;
			cd.friction = 0.0f;
					
			ballBody.createShape(cd);
			ballBody.setMassFromShapes();
	 }
}